package com.heima.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.admin.mapper.AdChannelMapper;
import com.heima.admin.mapper.AdSensitiveMapper;
import com.heima.admin.service.WemediaNewsAutoScanService;
import com.heima.common.aliyun.GreeTextScan;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.exception.CustException;
import com.heima.feigns.article.ArticleFeign;
import com.heima.feigns.wemedia.WemediaFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.CronExpression;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Version: V1.0
 */
@Service
@Slf4j
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {
    /**
     * admin发起远程调用
     */
    @Autowired
    WemediaFeign wemediaFeign;
    /**
     * 文本监测
     */
    @Autowired
    GreeTextScan greeTextScan;
    /**
     * 图片审核
     */
    @Autowired
    GreenImageScan greenImageScan;
    /**
     * 查找所有敏感词
     */
    @Autowired
    AdSensitiveMapper adSensitiveMapper;
    /**
     * 频道对应器
     */
    @Autowired
    private AdChannelMapper adChannelMapper;
    /**
     * 文章的远程调用
     */
    @Autowired
    ArticleFeign articleFeign;
    /**
     * http://heimaleadnewsoss.oss-cn-shanghai.aliyuncs.com/
     */
    @Value("${file.oss.web-site}")
    private String webSite;

    /**
     * 自媒体文章自动审核
     *
     * @param wmNewsId 自媒体文章id
     */
    @Override
    @GlobalTransactional
    public void autoScanByMediaNewsId(Integer wmNewsId) {
        //参数校验
        if (wmNewsId == null) {
            log.error("当前的审核id空");
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
            return;
        }
        //1.根据WmNews文章id查询文章
        WmNews wmNews = wemediaFeign.findById(wmNewsId);
        if (wmNews == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
            log.error("审核的自媒体文章不存在，自媒体的id:{}", wmNewsId);
            return;
        }
        /*
         * 判断文章的状态
         * 2.文章状态=4 人工审核通过，直接保存文章
         * 判断当前状态是否=4&&定时发布时间的毫秒值是否<=当前时间（以毫秒为单位）
         * 如果他定时发布的时间小于当前时间那么就直接保存
         * */
        if (wmNews.getStatus().equals(WmNews.Status.ADMIN_SUCCESS.getCode()) &&
                wmNews.getPublishTime().getTime() <= System.currentTimeMillis()) {
            //保存APP端文章相关数据
            saveAppArticle(wmNews);
            return;
        }
        /*
         * 4 文章状态=1 待审核
         * 判断当前状态是否=1
         * (1:抽取文章内容中的文本和图片
         * (2:自管理敏感词审核
         * (3:处理文字扫描
         * */
        if (wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())) {
            //抽取文章内容中的文本和图片
            Map<String, Object> contentAndImagesResult = handleTextAndImages(wmNews);
            //4.1自管理敏感词审核
            boolean isSensitiveScan = handleSensitive((String) contentAndImagesResult.get("content"), wmNews);
            if (!isSensitiveScan) {
                return;
            }
            //4.2阿里云审核文本内容
            boolean isTextScan = handleTextScan((String) contentAndImagesResult.get("content"), wmNews);
            if (!isTextScan) {
                return;
            }


            // 4.3阿里云图片审核
            boolean isImageScan = handleImagesScan((List) contentAndImagesResult.get("images"), wmNews);
            if (!isImageScan) {
                return;
            }
            //4.4判断文章发布时间大于当前时间，修改状态8
            if (wmNews.getPublishTime().getTime() > System.currentTimeMillis()) {
                updateWmNews(wmNews,WmNews.Status.SUCCESS.getCode(),"文本审核通过，待发布");
                return;
            }
            //5  保存文章相关数据
                saveAppArticle(wmNews);
            //TODO 6  同步索引库

        }
    }

    private boolean handleImagesScan(List images, WmNews wmNews) {
        //无图则无需审核
        if (images == null || images.size() == 0) {
            return true;
        }
        boolean flag = true;
        try {
            images = (List) images.stream().distinct().collect(Collectors.toList());
            Map map = greenImageScan.imageUrlScan(images);
            //审核不通过
            if (map.get("suggestion").equals("block")) {
                updateWmNews(wmNews, (short) 2, "文章图片有违规");
                flag = false;
            }
            //人工审核
            if (map.get("suggestion").equals("review")) {
                updateWmNews(wmNews, (short) 3, "文章图片有不确定元素");
                flag = false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            updateWmNews(wmNews, (short) 3, "阿里云审核失败，转入人工审核");
            flag = false;
        }
        return flag;
    }

    /**
     * 审核文内容-阿里云
     *
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleTextScan(String content, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = greeTextScan.greeTextScan(content);
            //审核不通过
            if (map.get("suggestion").equals("block")) {
                flag = false;
                updateWmNews(wmNews, (short) 2, "文本中内容有敏感词汇");
            }
            //需要人工审核
            if (map.get("suggestion").equals("review")) {
                flag = false;
                updateWmNews(wmNews, (short) 3, "文本中内容需要人工审核");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("文章阿里云内容审核失败，转入人工审核，e:{}", e);
            flag = false;
            updateWmNews(wmNews, (short) 3, "文章阿里云内容审核失败，需要人工审核");

        }
        return flag;

    }

    /**
     * 修改文章
     *
     * @param wmNews
     * @param status
     * @param msg
     */
    private void updateWmNews(WmNews wmNews, short status, String msg) {
        wmNews.setStatus(status);
        wmNews.setReason(msg);
        ResponseResult responseResult = wemediaFeign.updateWmNews(wmNews);
        if (!responseResult.getCode().equals(0)) {
            CustException.cust(AppHttpCodeEnum.WEMEDIA_UPDATE_ERROR);
        }
    }

    /**
     * 自管理敏感词审核
     *
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleSensitive(String content, WmNews wmNews) {
        boolean flag = true;
        //查询所有敏感词
        List<String> allSensitive = adSensitiveMapper.findAllSensitive();
        //初始化 DFA搜索
        SensitiveWordUtil.initMap(allSensitive);
        //匹配敏感词
        Map<String, Integer> stringIntegerMap = SensitiveWordUtil.matchWords(content);
        if (stringIntegerMap.size() > 0) {
            flag = false;
            updateWmNews(wmNews, (short) 2, "文章中包含了敏感词：" + stringIntegerMap);
        }
        return flag;
    }

    /**
     * 抽取文章内容中的文本和图片
     *
     * @param wmNews
     * @return
     */
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        //抽取文章文本
        String content = wmNews.getContent();
        List<Map> contentList = JSON.parseArray(content, Map.class);
        //接收文本
        /** contents是text*/
        StringBuilder contents = new StringBuilder();
        //文章标题 审核？
        //接收图片列表
        /** imageList是image*/
        ArrayList<String> imageList = new ArrayList<>();
        for (Map<String, String> map : contentList) {
            if (map.get("type").equals("text")) {
                contents.append(map.get("value"));
            }
            if (map.get("type").equals("image")) {
                imageList.add(map.get("value"));
            }
        }
        //解析文章封面的图片（注意文章封面地址没有前缀）
        if (StringUtils.isNotBlank(wmNews.getImages())) {
            String[] split = wmNews.getImages().split(",");
            for (String url : split) {
                imageList.add(webSite + url);
            }
        }
        //返回结果
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("content", contents.toString());
        resultMap.put("images", imageList);
        return resultMap;
    }

    /**
     * 保存APP端文章相关数据
     *
     * @param wmNews
     */
    private void saveAppArticle(WmNews wmNews) {
        //保存app相关文章
        ResponseResult responseResult = saveArticle(wmNews);
        if (!responseResult.getCode().equals(0)) {
            throw new RuntimeException("文章审核保存app文章失败");
        }
        Object data = responseResult.getData();
        //修改自媒体文章状态。状态为9 审核通过
        wmNews.setArticleId((Long) data);
        updateWmNews(wmNews, (short) 9, "文章审核通过");
    }

    /**
     * 保存app文章
     *
     * @param wmNews
     * @return
     */
    private ResponseResult saveArticle(WmNews wmNews) {
        //articleDto文章内容与文章信息表，存储已发布的文章
        ArticleDto articleDto = new ArticleDto();
        //如果文章ID存在则执行修改操作
        if (wmNews.getArticleId() != null) {
            /**
             * 发布库文章ID
             * 当文章下架后ap_article表的id还在
             * 这里就是判断id是否存在，如果存在就是修改文章
             * 如果不存在就是新增文章
             * 这里是把新增和修改写在一个方法里
             * */
            articleDto.setId(wmNews.getArticleId());
        }
        //articleDto.setPublishTime(wmNews.getPublishTime());
        //articleDto.setImages(wmNews.getImages());
        //把wmNews赋值给articleDto
        BeanUtils.copyProperties(wmNews, articleDto);
        /**
         * 文章布局
         * 这两个字段一个是文章布局一个是创建时间
         * 由于两个表字段不同所以他俩手动set进去
         * */
        articleDto.setLayout(wmNews.getType());
        articleDto.setCreatedTime(new Date());
        //设置频道
        //根据图文频道ID查询频道信息表
        AdChannel adChannel = adChannelMapper.selectById(wmNews.getChannelId());
        if (adChannel != null) {
            /**
             * 给频道做非空校验
             * 意思是，这是修改操作
             * 那么给这个文章重新赋频道id和频道名称
             * */
            articleDto.setChannelId(adChannel.getId());
            articleDto.setChannelName(adChannel.getName());
        }
        /**
         * 设置作者信息
         * 用Feign远程调用根据id查询作者信息的方法得到当前文章的自媒体用户信息表
         * */
        WmUser wmUser = wemediaFeign.findWmUserById(wmNews.getUserId());
        //给ap_article表存放登录用户名
          articleDto.setAuthorName(wmUser.getName());
        //把文章内容放进去
        articleDto.setContent(wmNews.getContent());
        //通过Feign调用远程方法保存文章ap_article的Dto传进去
        return articleFeign.saveArticle(articleDto);
    }

}
























